﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace Inspired.Euler
{
    /// <summary>
    /// You are given the following information, but you may prefer to do some research for yourself.
    /// 
    /// 1 Jan 1900 was a Monday.
    /// 
    /// Thirty days has September,
    /// April, June and November.
    /// All the rest have thirty-one,
    /// Saving February alone,
    /// Which has twenty-eight, rain or shine.
    /// And on leap years, twenty-nine.
    /// 
    /// A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.
    /// How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?
    /// </summary>
    public static class Problem019
    {
        /// <summary>
        /// How many Sundays fell on the first of the month during the twentieth century?
        /// </summary>
        [EulerProblem(19, Title = "How many Sundays fell on the first of the month during the twentieth century?")]
        public static long Solve()
        {
            return GetMonths()
                    .TakeWhile(day => day <= 365.25 * 101) // começa (internamente) em 1900
                    .Where(day => day % 7 == 0)
                    .Count();
        }


        private static IEnumerable<int> GetMonths()
        {
            int day = 366;
            int month = 1;
            int year = 1901;
            int[] days = new[]{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
            while (true)
            {
                yield return day;

                bool isSunday = day % 7 == 0;
                bool isLeap = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
                Debug.Assert(!isSunday || new DateTime(1900, 1, 1).AddDays(day - 1).Day == 1);
                Debug.Assert(!isSunday || new DateTime(1900, 1, 1).AddDays(day - 1).DayOfWeek == DayOfWeek.Sunday);

                day   += days[month - 1] + (month == 2 && isLeap ? 1 : 0);
                month += month == 12 ? -11: 1;
                year  += month == 1 ? 1 : 0;
            }
        }
    }
}
